programming4us
           
 
 
Programming

Programming Excel with VBA and .NET : Tasks in Visual Basic - Read and Write Files

- Free product key for windows 10
- Free Product Key for Microsoft office 365
- Malwarebytes Premium 3.7.1 Serial Keys (LifeTime) 2019
8/12/2011 9:09:01 AM
There are a number of different ways to read and write files in Visual Basic, and which you choose depends on what you are trying to do, as described in Table 1.
Table 1. File-access techniques in Excel Visual Basic
TechniqueUse to
Intrinsic functionsRead or write simple datafiles
FileSystemObjectCreate files, folders, and control file attributes
Workbooks, Workbook objectsCreate, open, and save Excel workbook files; import datafiles into workbooks
XMLMap objectImport or export XML datafiles from a workbook

In short, you shouldn't assume the Visual Basic intrinsic functions are the best way to read and write files in all situations. Actually, I prefer the FileSystemObject for most general file-access tasks, but it's important to be thorough, so I'll cover the intrinsic file-access functions here (Table 2).

Table 2. Visual Basic's intrinsic file-access functions
CategoryFunctionUse to
AccessCloseClose an open file
 FileCopyCopy a file
 FreeFileGet a file number for Open
 Lock...UnlockPrevent others from accessing all or part of a file
 LOFGet the length of an open file in bytes
 OpenOpen a file
 ResetClose all open files
AttributesFileAttrGet the attributes of an open file
 FileDateTimeGet the date that a file was created or changed
 FileLenGet the length of a file in bytes before opening it
 GetAttrGet the attributes of a file, folder, or volume label
 SetAttrChange the attributes of a file, folder, or volume label
DrivesChDirSet the current folder
 ChDriveSet the current drive
 CurDirGet the current folder
 MkDirCreate a new folder
 RmDirDelete an empty folder
ManageDirList files in a folder
 KillDelete a file
 NameRename a file
ReadGetRead data from an open binary or random-access file
 EOFTest you have reached the end of the file
 Input #Read records from an open sequential file
 Line Input # Read a line from an open sequential file
 LocReturn the current position within a file
 SeekGet or set the current position within a file
WritePrint #Write a line to an open sequential file
 PutWrite data to an open binary or random-access file
 SpcInsert blank spaces in a sequential file
 TabInsert tab characters in a sequential file
 Width #Set the width of a sequential file
 Write #Write records to a sequential file

The functions in Table 2 reflect the fact that there are three different types of file access in Visual Basic:


Sequential access

Reads files one line at a time


Random access

Reads files as a collection of fixed-length records


Binary access

Reads files as an arbitrary number of bytes

All of these types of access follow the same pattern, which is based on a very old programming concept called file handles :

  1. Use FreeFile to get a number that is available for use as a file handle.

  2. Open the file using that number and the chosen file-access method.

  3. Read data from the file using Input # (sequential access) or Get (random or binary access), or write data using Print #, Write # (sequential), or Put (random or binary).

  4. Close the file handle.

The modern approach, such as that used by the FileSystemObject, is to use object references rather than numeric file handles.


Of the three types of file access, binary is the most useful in today's world because it allows you to read an entire file into a variable with a single statement. It is by far the fastest way to get the contents of a file. The following QuickRead function opens and reads a file and returns the data it contains as a string variable:

    ' Reads a file into a string.
Function QuickRead(fname As String) As String
Dim i As Integer, res As String, l As Long
' Get a free file handle.
i = FreeFile
' Get the length of the file
l = FileLen(fname)
' Create a string to contain the data.
res = Space(l)
' Open the file.
Open fname For Binary Access Read As #i
' Read the whole file into res.
Get #i, , res
' Close the file
Close i
' Return the string.
QuickRead = res
End Function

How big of a file can you read this way? Pretty big! I had no problem loading an 8.4 MB art file using this technique. String variables can be very large in Visual Basic. Similarly, you can write files very quickly with binary access. The following QuickWrite function saves a string as a file and returns True if it succeeded:

    ' Writes data to a file.
Function QuickWrite(data As String, fname As String, _
Optional overwrite As Boolean = False) As Boolean
Dim i As Integer, l As Long
' If file exists and overwrite is True, then
If Dir(fname) <> "" Then
If overwrite Then
' delete the file.
Kill fname
Else
' else, return False and exit.
QuickWrite = False
Exit Function
End If
End If
' Get a free file handle.
i = FreeFile
' Get the length of the file
l = Len(data)
' Open the file.
Open fname For Binary Access Write As #i Len = l
' Write the string to the file.
Put #i, , data
' Close the file
Close i
' Return True.
QuickWrite = True
End Function



This approach was first pointed out to me by Mark Chase, senior developer on Basic at Microsoft. He deserves credit for clear thinking and also for being a darn nice guy. You can test that these functions work by running the following code from the sample workbook:

    Sub DemoQuickReadWrite( )
Dim pth As String, data As String
' Get the folder that this workbook is in.
pth = ThisWorkbook.Path
' Read the ReadMe.txt file.
data = QuickRead(pth & "\in.txt")
' Display the file
Debug.Print data
' Change the file.
data = Replace(data, "text", "data")
' Save the file.
Debug.Print QuickWrite(data, pth & "\out.txt", True)
End Sub

1. Sequential Access

Sequential access reads and writes files one line at a time. In the past, sequential access was often used to write reports or other data to human-readable files. For example, the following WriteArray function writes a two-dimensional array to disk as a comma-delimited file using sequential access:

    ' Writes a two-dimensional array to a comma-delimited file.
' (Use to create CSV file out of a selected range.)
Function WriteArray(arr As Variant, fname As String, _
Optional overwrite As Boolean = False) As Boolean
Dim lb1 As Long, lb2 As Long, ub1 As Long, ub2 As Long
Dim i As Integer, rows As Long, cols As Long, rec As String
' If arr isn't an array, return False and exit.
If Not IsArray(arr) Then WriteArray = False: Exit Function
' Get bounds for For loops.
lb1 = LBound(arr, 1)
lb2 = LBound(arr, 2)
ub1 = UBound(arr, 1)
ub2 = UBound(arr, 2)
' If file exists and overwrite is True, then
If Dir(fname) <> "" Then
If overwrite Then
' delete the file.
Kill fname
Else
' else, return False and exit.
WriteArray = False
Exit Function
End If
End If
' Get a free file handle.
i = FreeFile
' Open the file.
Open fname For Append As #i
' For each row in the array.
For rows = lb1 To ub1
' For each column in the array.
For cols = lb2 To ub2
rec = rec & arr(rows, cols) & ", "
Next
' Remove the last ", " from rec.
rec = Left(rec, Len(rec) - 2)
' Write rec to the file.
Print #i, rec
' Clear rec
rec = ""
Next
' Close the file
Close i
' Return True.
WriteArray = True
End Function


That looks complicated, but the actual file-access code (in bold) is really very simple and follows the pattern described previously: get a file handle, open the file, read or write to the file, close the file. Sequential access is suited to this task since you are building the string data one line at a time as you loop over the rows in the array.

Perhaps a better approach to this task would be to build a string from the array in one procedure and then save that string using the QuickWrite function. That approach would isolate file access in one place (QuickWrite) instead of integrating it into the task of converting the array into a string. The following code shows that alternate approach:

    ' Better approach -- don't integrate file access within
' array conversion task.
Function TableToCSV(arr As Variant) As String
Dim lb1 As Long, lb2 As Long, ub1 As Long, ub2 As Long
Dim rows As Long, cols As Long, rec As String
' If arr is not an array, return "" and exit.
If Not IsArray(arr) Then TableToCSV = "": Exit Function
' Get bounds for For loops.
lb1 = LBound(arr, 1)
lb2 = LBound(arr, 2)
ub1 = UBound(arr, 1)
ub2 = UBound(arr, 2)
For rows = lb1 To ub1
For cols = lb2 To ub2
rec = rec & arr(rows, cols) & ", "
Next
' Remove last ", " and add carriage return/line feed.
rec = Left(rec, Len(rec) - 2) & vbCrLf
Next
TableToCSV = rec
End Function

Using TableToCSV instead of WriteArray involves the extra step of calling QuickWrite, but the logic is still very clear:

    Sub DemoTableToCSV( )
Dim arr As Variant, data As String, pth As String
pth = ThisWorkbook.Path
' Get cells from the active worksheet.
arr = ActiveSheet.UsedRange.Value
' If the range contains cells.
If IsArray(arr) Then
' Convert array to CSV.
data = TableToCSV(arr)
If data <> "" Then
' Save the result
QuickWrite data, pth & "\selection.csv", True
' Display the result
Debug.Print data
End If
End If
End Sub

2. Random Access

Random-access files are read or written one record at a time. In this case, record usually means a fixed-size data structure identified by a user-defined type. Because Visual Basic knows the length of each record, you can jump to any record in the file using the Seek statement (that's what makes the access random).

In order to use random access , you must first define the structure of your record with a Type statement. You then declare a variable with that type and use it to read and/or write records to the file. I'm not going to show you how to do all that, because XML files and databases both provide a much better approach for storing and retrieving structured data.

Why is random access not such a great approach? A few reasons:

  • The records are fixed-length by definition, which means names, addresses, and other variable-length data must be stored in fixed-length strings. You have to correctly guess the maximum size of those items during design.

  • Changes to your data structure, such as adding a field, means you have to convert all of your existing datafiles. You have to write code to open, convert, and save files using the new structure. (In programming circles this is called tying your data structure to your implementation, and it's a bad thing.)

  • You're programming in Excel! You already have better tools for doing these types of tasks.

3. Common Tasks

In addition to reading and writing files, you also often need to manage the files on a computer. The most common tasks are listed in Table 3.

Table 3. Common tasks for Visual Basic's intrinsic file functions
TaskFunctionComments
Check if file existsDirAlso used to list files in a folder.
Delete a fileKillDeletes a file if it is not locked or read-only.
Get the current folderCurDirExcel may change the current folder when a workbook is saved or opened by the user.
Change current folderChDirYou can use characters like .. to move up one folder.
Change current driveChDriveOnly the first letter from the argument is used.
Create a folderMkDirMay include path specifiers like . (current folder) or .. (up one folder). Does not change the current folder.
Delete a folderRmDirFolder must be empty before it can be deleted.
Get/change file attributesFileAttrFile attributes include hidden, read-only, archive.
Make a backup copyFileCopyCopies an existing file to a new filename.
Rename a fileNameChanges a filename.

In general, it is not a good idea to get the current folder (CurDir) or change the current folder (ChDir) from Visual Basic when working with Excel because saving or opening a file from the Excel user interface may subsequently change the current folder. It is a better practice to use the path properties provided by Excel objects when working with folders in Excel.

For example, the following code displays the paths available for various Excel objects:

    Sub ShowPaths( )
Dim wbPth As String, appPth As String, stPth As String, _
altPth As String, tpPth As String, adPth As String
wbPth = ThisWorkbook.Path
appPth = Application.Path
stPth = Application.StartupPath
altPth = Application.AltStartupPath
tpPth = Application.TemplatesPath
adPth = Application.AddIns(1).Path
Debug.Print "Workbook path:", wbPth
Debug.Print "Application path:", appPth
Debug.Print "Startup path: ", stPth
Debug.Print "Alt startup path:", altPth
Debug.Print "Template path:", tpPth
Debug.Print "Add-in path: ", adPth
End Sub

I often use ThisWorkbook.Path within my samples to get or save files associated with the current workbook. That strategy keeps all of the related files in the same folder, so it is easier to copy the samples to a new location or to install them on your computer. Alternately, you may choose to create a fixed folder location for use in your code such as shown here:

    ' A fixed path.
Const SAMPLEPTH = "\Excel\Samples"

' Run once to create folder.
Sub CreateSamplesFolder( )
' Create the SAMPLEPTH folder
On Error Resume Next
MkDir "\Excel"
MkDir "\Excel\Samples"
If Err Then _
MsgBox ("Couldn't create folder. It may already exist.")
End Sub

Using a fixed location for your files poses the problem illustrated by the preceding exception handling: the folder may already exist! That's another reason to use the ThisWorkbook.Path approach.

You can use the Dir function to check whether a file exists in a folder or to get a list of all of the files in a folder. When getting a list of files, Dir acts a little strangely. The first time you call it, specify the folder you want to search; then call Dir without an argument to get the next file in the folder, as shown here:

    Function GetFiles(filepath As String) As Variant
Dim arr( ) As String, fname As String, count As Integer
' Get the first file.
fname = Dir(filepath & "\*")
Do Until fname = ""
count = count + 1
ReDim Preserve arr(count)
arr(count - 1) = fname
' Get next file.
fname = Dir( )
Loop
' Return the array
GetFiles = arr
End Function

Dir does not order the files it returns alphabetically, so you may need to sort the list before displaying it. For example, the following code uses the GetFiles function to list the files in the current workbook's folder:

     Sub DemoGetFiles( )
Dim flist As Variant, str As String
flist = GetFiles(ThisWorkbook.Path)
' Sort the file list
Text.SortArray (flist)
str = Join(flist, vbCrLf)
Debug.Print str
End Sub

The FileSystemObject provides more extensive methods for working with files, folders, and drives.

Other -----------------
- Programming Excel with VBA and .NET : Tasks in Visual Basic - Get Dates and Times
- Programming Excel with VBA and .NET : Tasks in Visual Basic - Work with Text
- A Technical Overview of the Mobile Web : THE TECHNICAL CHALLENGES OF MOBILE DEVICES (part 2)
- A Technical Overview of the Mobile Web : THE TECHNICAL CHALLENGES OF MOBILE DEVICES (part 1) - Physical Constraints
- Parallel Programming with Microsoft Visual Studio 2010 : Task Parallelism - Unhandled Exceptions in Tasks
- Parallel Programming with Microsoft Visual Studio 2010 : Introduction to Parallel Tasks
- jQuery 1.3 : DOM Manipulation - Moving elements
- .NET Debugging : Introduction to the Tools - .NET 2.0—Redistributable & .NET 2.0—SDK
- .NET Debugging : Managed Heap and Garbage Collection
- Context and Interception : Custom Component Services (part 3) - The Transaction Management Service
- Context and Interception : Custom Component Services (part 2) - The Logbook Service
- Context and Interception : Custom Component Services (part 1) - Building a Custom Context Attribute & Installing a Custom Message Sink
- Software Testing with Visual Studio Team System 2008 : Data-driven unit testing
- Software Testing with Visual Studio Team System 2008 : Unit testing an ASP.NET application
- Microsoft Enterprise Library : Error Management Made Exceptionally Easy - Replacing an Exception & Logging an Exception
- Microsoft Enterprise Library : Error Management Made Exceptionally Easy - Diving in with a Simple Example
- iPhone Programming : Connecting to the Network - Embedding a Web Browser in Your App
- iPhone Programming : Connecting to the Network - Detecting Network Status
- Parallel Programming with Microsoft Visual Studio 2010 : Introduction to Parallel Programming - Software Patterns
- Parallel Programming with Microsoft Visual Studio 2010 : Introduction to Parallel Programming - Multicore Computing & Speedup
 
 
 
Top 10
 
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
- Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
- Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
- First look: Apple Watch

- 3 Tips for Maintaining Your Cell Phone Battery (part 1)

- 3 Tips for Maintaining Your Cell Phone Battery (part 2)
programming4us programming4us